/**
 * 
 */
package org.statewalker.core;

import org.statewalker.core.IState.ICallback;
import org.statewalker.fsm.FsmProcess;
import org.statewalker.fsm.IFsmStateListener;
import org.statewalker.fsm.providers.FsmStateProvider;

/**
 * @author kotelnikov
 */
public class Process extends FsmProcess<IState, IEvent> {

    protected ICallback fCallback = new ICallback() {
        public void finish(IEvent event) {
            try {
                setEvent(event);
            } finally {
                fLock.unlock();
            }
        }
    };

    private IProcessContext fContext;

    private ProcessDescriptor fDescriptor;

    protected ILock fLock;

    /**
     * @param mask
     * @param provider
     * @param listener
     */
    public Process(
        ProcessDescriptor descriptor,
        final IStateExecutor executor,
        IProcessContext context,
        ILock lock,
        String mainKey,
        int mask) {
        super(null, null, mask);
        fDescriptor = descriptor;
        fContext = context;
        fLock = lock;
        fStateListener = new IFsmStateListener<IState, IEvent>() {
            private void handle(IState state, IEvent event, boolean activate) {
                boolean ok = false;
                fLock.lock();
                try {
                    if (activate) {
                        executor.activateState(Process.this, state, event);
                    } else {
                        executor.deactivateState(Process.this, state, event);
                    }
                    ok = true;
                } finally {
                    try {
                        if (!ok) {
                            fLock.unlock();
                        }
                    } finally {
                        fLock.waitForUnlock();
                    }
                }
            }

            public void onActivate(IState parent, IState state, IEvent event) {
                handle(state, event, true);
            }

            public void onDeactivate(IState parent, IState state, IEvent event) {
                handle(state, event, false);
            }

            public void onTransition(
                IState parent,
                IState prev,
                IEvent event,
                IState next) {
            }
        };
        fProvider = new FsmStateProvider<IState, IEvent>(
            fDescriptor.fRegistry,
            mainKey) {

            @Override
            protected String calculateParentEventKey(String eventKey) {
                int idx = eventKey.lastIndexOf("/");
                if (idx > 0) {
                    String parentKey = eventKey.substring(0, idx);
                    return parentKey;
                }
                return super.calculateParentEventKey(eventKey);
            }

            @Override
            protected String getEventKey(IEvent event) {
                return event.getKey();
            }

            @Override
            protected String getStateKey(IState state) {
                return state != null ? state.getKey() : null;
            }

            @Override
            protected IState newState(
                IState parent,
                IState prev,
                IEvent event,
                String stateKey) {
                return fDescriptor.newState(Process.this, event, stateKey);
            }
        };

    }

    public IProcessContext getContext() {
        return fContext;
    }

    public ICallback getStateCallback() {
        return fCallback;
    }

}
